﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Text.RegularExpressions;
using System.Text;
using System.Linq;
using System.Windows.Forms;
using System.IO;
using RazorEngine;
using System.Reflection;
using System.Collections.Generic;

namespace UnitFactory {
    [TestClass]
    public class Factory {
        public string GenerateEntityBase(string input, bool isNotify = false) {
            var pattern = @"(?<=create table\s+)(?<class>\w+_?\w+)\((?<props>(([^\(\)])|(?<open>\()|(?<-open>\)))*)(?(open)(?!))\)";

            var r = new Regex(pattern);
            var x = r.Matches(input);
            var sb = new StringBuilder();
            foreach (Match x2 in x) {
                foreach (Capture item in x2.Groups["class"].Captures) {
                    if (isNotify) {
                        sb.AppendLine(string.Format("public class {0} : INotifyPc {1}", item.Value, "{"));
                        sb.AppendLine("public Command Act { get; set; }");
                        sb.AppendLine("public object ActParam { get; set; }");
                        sb.AppendLine("public void OnPropertyChanged(string pn) {");
                        sb.AppendLine("if (PropertyChanged != null) {");
                        sb.AppendLine("PropertyChanged.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(pn));");
                        sb.AppendLine("}");
                        sb.AppendLine("}");
                        sb.AppendLine("public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;");
                    } else {
                        sb.AppendLine(string.Format("public class {0}{1}", item.Value, "{"));
                    }
                }
                foreach (Capture item in x2.Groups["props"].Captures) {
                    //Console.WriteLine(item.Value);
                    //var row2 = item.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                    var row = Regex.Split(item.Value, @"\r\n");
                    foreach (var prop in row) {
                        var pattern2 = @"(?<!-+\w+\s*[\r\n]\s*?)(?<=[\r\n,\[]?\s*)\w+(?=\]?)\b";
                        var pattern3 = @"\s?\[?(int|tinyint|varchar|bit|datetime|decimal|float|image|money|ntext|nvarchar|smalldatetime|smallint|text|bigint|binary|char|nchar|numeric|real|smallmoney|sql_variant|timestamp|uniqueidentifier|varbinary|xml)\]?\s?";
                        var pantter4 = @"\((?:\d{1,5}|max)\)?";
                        var pantter5 = @"(?<=references\s+)\w+(?=\W)";
                        var propName = Regex.Match(prop, pattern2).Value;
                        var pt = Regex.Match(prop, pattern3);
                        var propType = SqlTypeName2DotNetType(pt.Groups[0].Value);
                        if (!string.IsNullOrEmpty(propName) && !string.IsNullOrEmpty(propType))
                            sb.AppendLine(string.Format("public {0} {1}{2}get;set;{3}", propType, propName, "{", "}"));

                        //var relationship = Regex.Match(prop, pantter5).Value;
                        //if (!string.IsNullOrEmpty(relationship)) {
                        //    Console.WriteLine(relationship);
                        //}
                    }
                }
                foreach (Capture item in x2.Groups["class"].Captures) {
                    sb.AppendLine(string.Format("{0}", "}"));
                }
            }
            //Console.WriteLine(sb.ToString());
            //Clipboard.SetText(sb.ToString());
            return sb.ToString();
        }
        /// <summary>  
        /// 将SQLServer数据类型（如：varchar）转换为.Net类型（如：String）
        /// </summary>  
        /// <param name="sqlTypeString">SQLServer数据类型</param>  
        /// <returns>net type string</returns>  
        public static string SqlTypeName2DotNetType(string sqlTypeString) {
            if (string.IsNullOrEmpty(sqlTypeString)) return string.Empty;
            string[] SqlTypeNames = new string[] { "int", "varchar","bit" ,"datetime","decimal","float","image","money", 
   "ntext","nvarchar","smalldatetime","smallint","text","bigint","binary","char","nchar","numeric",    "real","smallmoney", "sql_variant","timestamp","tinyint","uniqueidentifier","varbinary","xml"};
            string[] DotNetTypes = new string[] {
                "int", "string","bool" ,"DateTime","Decimal","Double","Byte[]","Single", 
   "string","string","DateTime","Int16","string","Int64","Byte[]","string","string","Decimal", 
   "Single","Single", "Object","Byte[]","Byte","Guid","Byte[]","string"};
            var mark = sqlTypeString.ToLower().Trim();
            int i = Array.IndexOf(SqlTypeNames, mark);
            return DotNetTypes[i];
        }

        public string GenerateEntityCtx(string input, string dbc) {
            var pattern = @"(?<=create table\s+)(?<class>\w+_?\w+)\((?<props>(([^\(\)])|(?<open>\()|(?<-open>\)))*)(?(open)(?!))\)";
            var r = new Regex(pattern);
            var x = r.Matches(input);
            var sb = new StringBuilder();
            sb.AppendLine(string.Format("public class {0}:DbContext{1}", dbc, "{"));
            foreach (Match x2 in x) {
                foreach (Capture item in x2.Groups["class"].Captures) {
                    sb.AppendLine(string.Format("public DbSet<{0}> p{1} {2}get;set;{3}", item.Value, item.Value, "{", "}"));
                }
            }
            sb.AppendLine(string.Format("public {0}(string con):base(con){1}", dbc, "{"));
            sb.AppendLine(string.Format("{0}", "}"));
            sb.AppendLine(string.Format("{0}", "}"));
            //Clipboard.SetText(sb.ToString());
            return sb.ToString();
        }

        private void GenerateEntitysCtx(string entitypath, string ctxpath, string entitysql, string ctxsql) {
            using (var sw = new StreamWriter(File.Open(entitypath, FileMode.OpenOrCreate,
                FileAccess.Write))) {
                var content = Razor.Parse(Properties.Resources.generalcodefile, new {
                    namesp = "Dtm.Core",
                    clas = entitysql,
                    ns1 = "using ArithCollect;",
                    ns2 = "",
                });
                sw.Write(content);
                sw.Flush();
            }
            using (var sw = new StreamWriter(File.Open(ctxpath, FileMode.OpenOrCreate, FileAccess.Write))) {
                var content = Razor.Parse(Properties.Resources.generalcodefile, new {
                    namesp = "Dtm.Dal",
                    clas = ctxsql,
                    ns1 = "using System.Data.Entity;",
                    ns2 = "using Dtm.Core;",
                });
                content = content.Replace("&lt;", "<");
                content = content.Replace("&gt;", ">");
                sw.Write(content);
                sw.Flush();
            }
        }
        public void GenerateVmh() {
            var path=@"E:\tfs\pddvscom\DevTradingMarket\DTm.Core\Vmh.cs";
            using (var sw=new StreamWriter(File.Open(path,FileMode.OpenOrCreate,FileAccess.Write))) {
                sw.Write(Properties.Resources.Vmh);
                sw.Flush();
            }
        }
        [TestMethod]
        public void GenerateEntitysCtx() {
            var entitypath = @"E:\tfs\pddvscom\DevTradingMarket\DTm.Core\Vmentitys.cs";
            var ctxpath = @"E:\tfs\pddvscom\DevTradingMarket\Dtm.Dal\Vmctx.cs";
            GenerateEntitysCtx(entitypath, ctxpath, GenerateEntityBase(Properties.Resources.vm, true), GenerateEntityCtx(Properties.Resources.vm, "Vmctx"));
            GenerateVmh();
        }
        [TestMethod]
        public void GenerateEntitysCtx2() {
            var entitypath = @"E:\tfs\pddvscom\DevTradingMarket\DTm.Core\Entitys.cs";
            var ctxpath = @"E:\tfs\pddvscom\DevTradingMarket\Dtm.Dal\DevtkCtx.cs";
            GenerateEntitysCtx(entitypath, ctxpath, GenerateEntityBase(Properties.Resources.devtradingmarket), GenerateEntityCtx(Properties.Resources.devtradingmarket, "DevtkCtx"));
            Console.WriteLine("write to : doc\\Codebag.txt");

        }
        #region MyRegion

        [TestMethod]
        public void Main() {
            CreateCtxProxy();
            CreateIWorklog();
            CreateVmStyleConverter();
            CreateVmUiStyle();
        }
        bool SaveTo(string dir, string sfn, string content) {
            var r = false;
            if (!Directory.Exists(dir)) {
                Directory.CreateDirectory(dir);
            }
            var path = string.Format("{0}\\{1}", dir, sfn);
            if (File.Exists(path)) File.Delete(path);
            using (var sw = new StreamWriter(File.Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))) {
                sw.Write(content); sw.Flush();
            }
            return r;
        }
        static string thedllname = Assembly.GetExecutingAssembly().GetName().Name;
        //@"E:\workroom\tfs\projspace\DevTeamSynergyTool\Dtst.View.Main\Style";
        private string vm_style_dir;
        public string Vm_style_dir {
            get {
                if (!string.IsNullOrEmpty(vm_style_dir))
                    return vm_style_dir;
                else {
                    var cc = Environment.CurrentDirectory;
                    cc = Environment.CurrentDirectory.Substring(0, cc.IndexOf(thedllname));
                    vm_style_dir = string.Format("{0}Dtst.View.Main\\Style", cc);
                    return vm_style_dir;
                }
            }
        }
        //@"E:\workroom\tfs\projspace\DevTeamSynergyTool\Dtst.Biz.Core\Commport";
        private string core_comm_dir;
        public string Core_comm_dir {
            get {
                if (!string.IsNullOrEmpty(core_comm_dir))
                    return core_comm_dir;
                else {
                    var cc = Environment.CurrentDirectory;
                    cc = Environment.CurrentDirectory.Substring(0, cc.IndexOf(thedllname));
                    core_comm_dir = string.Format("{0}Dtst.Biz.Core\\Commport", cc);
                    return core_comm_dir;
                }
            }
        }
        private string solution_dir;
        public string Solution_dir {
            get {
                if (!string.IsNullOrEmpty(solution_dir))
                    return solution_dir;
                else {
                    var cc = Environment.CurrentDirectory;
                    cc = Environment.CurrentDirectory.Substring(0, cc.IndexOf(thedllname));
                    return cc;
                }
            }
        }
        void CreateCtxProxy() {
            //var sfn = "ctxproxy.cs";
            //string entitypath = "Dtst.Biz.Core";
            //Assembly entitydll = Assembly.Load(entitypath);
            //IEnumerable<Type> thedbEntitys = from item in entitydll.GetTypes()
            //                                 where Regex.IsMatch(item.Name, "Lc_|Note_|R_|Role_|State_|Res_")
            //                                 select item;
            ////var vm=entitys=
            //var content = Razor.Parse(Properties.Resources.ctxproxy, new { namesp = "Dtst.Biz.Dal.Dbs", dbctxname = "worklog", thedbEntitys = thedbEntitys });
            //SaveTo(Core_comm_dir, sfn, content);
        }
        void CreateIWorklog() {
            //var sfn = "IWorklog.cs";
            //var x = typeof(Dtst.Biz.Dal.Commport.WorklogDesign);
            //var mis = new HashSet<MethodInfo>(x.GetMethods());
            //var bmis = new HashSet<MethodInfo>(x.BaseType.GetMethods());
            //mis.RemoveWhere(mi => bmis.Contains(mi, Acex.CreateComparer<MethodInfo, string>(mi2 => mi2.Name)));

            //var content = Razor.Parse(Properties.Resources.IWorklog, new { namesp = "Dtst.Biz.Dal.Commport", iname = "IWorkLog", mis = mis });
            //SaveTo(Core_comm_dir, sfn, content);
        }
        void CreateVmStyleConverter() {
            var sfn = "vmstyleconverter.cs";
            var content = Razor.Parse(Properties.Resources.VmStyleConverter, new { theNamespace = "Dtst.View.Main" });
            SaveTo(Vm_style_dir, sfn, content);
        }
        void CreateVmUiStyle() {
            var sfn = "vmuistyle.xaml";
            var entitypath = "Dtst.Biz.Core";
            Assembly entitydll = Assembly.Load(entitypath);
            Type[] entitytps = entitydll.GetTypes();
            IEnumerable<Type> vmtps = from item in entitytps where item.Name.Split('_').Last() == "Vm" select item;
            //业务辅助界面元素类型
            IEnumerable<Type> mvmtps = from item in vmtps where Regex.IsMatch(item.Name, "Model_Vm") select item;
            //主体业务类型
            IEnumerable<Type> unmvmtps = from item in vmtps.ToArray() where !Regex.IsMatch(item.Name, "Model_Vm") select item;

            Assembly thedll = Assembly.Load(thedllname);
            var theNamespace = "Dtst.View.Main";

            List<EntityType> ets = new List<EntityType>();//辅助业务界面元素
            foreach (Type item in mvmtps) {
                var et = new EntityType { entityName = item.Name };
                foreach (PropertyInfo item2 in item.GetProperties()) {
                    if (item2.Name != "RelatedEntity" && item2.Name != "ActParam" && item2.Name != "Act" && item2.Name != "ID" && item2.PropertyType != item && item2.PropertyType.Name != "ICollection`1") {
                        et.props.Add(new EntityProp { propName = item2.Name });
                    }
                }
                ets.Add(et);
            }
            List<EntityType> etdts = new List<EntityType>();
            foreach (Type item in unmvmtps) {
                var et = new EntityType { entityName = item.Name };
                foreach (PropertyInfo item2 in item.GetProperties()) {
                    if (item2.Name != "ID" && item2.PropertyType != item && item2.PropertyType.Name != "ICollection`1") {
                        et.props.Add(new EntityProp { propName = item2.Name, propTypeName = item2.PropertyType.Name, propGenericType1 = item2.PropertyType.GenericTypeArguments.Count() == 0 ? string.Empty : item2.PropertyType.GenericTypeArguments[0].Name });
                    }
                }
                etdts.Add(et);
            }
            /*theNamespace:Dtst.View.Main*/
            var content = Razor.Parse(Properties.Resources.vmuistyle, new { theNamespace = theNamespace, ets = ets, etdts = etdts, mvmtps = mvmtps });
            //content = content.Replace("&lt;", "<");
            //content = content.Replace("&gt;", ">");
            SaveTo(Vm_style_dir, sfn, content);
        }
        #endregion
    }

    public class EntityType {
        public string entityName;
        public string EntityName {
            get {
                if (Regex.IsMatch(entityName, "Model_Vm")) { return entityName.Substring(0, entityName.Length - "Model_Vm".Length); } else { return entityName; }
            }
        }
        public List<EntityProp> props;
        public EntityType() { props = new List<EntityProp>(); }
    }
    public class EntityProp {
        public string propName;
        public string propTypeName;
        public string propGenericType1;
    }
}
